package math;

import org.apache.commons.math3.analysis.differentiation.DerivativeStructure;
import org.apache.commons.math3.analysis.differentiation.UnivariateDifferentiableFunction;
import org.apache.commons.math3.analysis.solvers.AbstractUnivariateDifferentiableSolver;
import org.apache.commons.math3.analysis.solvers.NewtonRaphsonSolver;
import org.apache.commons.math3.exception.DimensionMismatchException;
import org.apache.commons.math3.exception.TooManyEvaluationsException;
import org.apache.commons.math3.util.FastMath;
import com.chaintor.demo.math.NoTooManyNewtonRaphsonSolver;

public class NewtonPriceTreeExample {
    public static void main(String[] args) {
        // 创建牛顿迭代求解器
        //NewtonRaphsonSolver solver = new NewtonRaphsonSolver(1e-6);
        NoTooManyNewtonRaphsonSolver solver = new NoTooManyNewtonRaphsonSolver(1e-6);
        // 设置求解器的初始猜测值和收敛条件
        double initialGuess = -0.5; // 初始猜测值
        int maxIterations = 100; // 最大迭代次数
        //初始化值
        double[] pcf = {};
        double[] icf = {};
        double[] aicf = {};
        double[] pl = {};
        double[] delta_t = {};
        // 执行牛顿迭代计算
        PriceTreeFunction doFunc = new PriceTreeFunction(0.5,0,pcf,icf,aicf,pl,delta_t);
        double result = solver.solve(
                maxIterations,
                doFunc,
                initialGuess
        );
        // 输出计算结果
        System.out.println("方程的解为:X= " + result);
        System.out.println("y="+doFunc.value(result));
    }
}

// PriceTree实现类，用于封装目标函数
class PriceTreeFunction implements UnivariateDifferentiableFunction {
    private double y;
    private int mode;
    private double[] pcf;
    private double[] icf;
    private double[] aicf;
    private double[] pl;
    private double[] delta_t;

    //构造函数传入初始化参数
    public PriceTreeFunction(double y,int mode,double[] pcf, double[] icf, double[] aicf, double[] pl, double[] delta_t) {
        //根据实际函数调整
        this.y = y;
        this.mode = mode;
        this.pcf = pcf;
        this.icf = icf;
        this.aicf = aicf;
        this.pl = pl;
        this.delta_t = delta_t;
    }

    //函数实现递归函数
    public double price_tree(int mode, double x, int i, int j, int n, double[] pcf, double[] icf, double[] aicf, double[] pl, double[] delta_t,double[][] v, double[] k) {//simpleMatrix r
        //实现略
        if (i == 0 && j == 0) {
            return v[0][0];
        } else {
            if (i == j) {
                return price_tree(mode, x, i - 1, 0, n, pcf, icf, aicf, pl, delta_t, v, k);
            } else {
                return price_tree(mode,x,i,j+1, n, pcf, icf, aicf, pl, delta_t, v, k);
            }
        }
    }

    //函数调用入口
    public double value(double x) {
        double[][] v = {};
        double[] k ={};
        double priceTree = price_tree(this.mode,x,0,0,0,this.pcf,this.icf,this.aicf,this.pl,this.delta_t,v,k);
        return priceTree-this.y;
    }

    //导函数万能公式
    public DerivativeStructure value(DerivativeStructure t) throws DimensionMismatchException {
        double x =  t.getValue();
        double y = this.value(x);
        double y0 = this.value(x+1E-10);
        double y1 = this.value(x-1E-10);
        double dy = (y0-y1)/(2*1E-10);
        DerivativeStructure ds = new DerivativeStructure(1, 1, y, dy);
        return ds;
    }

    //自实现牛顿迭代不报TooManyEvaluationsException错，当TooManyEvaluationsException时返回结果值
    public  class NoTooManyNewtonRaphsonSolver extends AbstractUnivariateDifferentiableSolver {
        private static final double DEFAULT_ABSOLUTE_ACCURACY = 1.0E-6D;

        public NoTooManyNewtonRaphsonSolver(){
            this(DEFAULT_ABSOLUTE_ACCURACY);
        }

        public NoTooManyNewtonRaphsonSolver(double absoluteAccuracy){
            super(absoluteAccuracy);
        }

        //重写迭代方法去除错误返回
        protected double doSolve() throws TooManyEvaluationsException {
            double startValue = getStartValue();
            double absoluteAccuracy = getAbsoluteAccuracy();

            double x0 = startValue;
            double x1;
            while (true) {
                try {
                    final DerivativeStructure y0 = computeObjectiveValueAndDerivative(x0);
                    x1 = x0 - (y0.getValue() / y0.getPartialDerivative(1));
                    if (FastMath.abs(x1 - x0) <= absoluteAccuracy) {
                        return x1;
                    }

                    x0 = x1;
                }catch (TooManyEvaluationsException e){
                    return x0;
                }
            }
        }
    }

}

